// 给定一个单链表 L：L0→L1→…→Ln-1→Ln ，
// 将其重新排列后变为： L0→Ln→L1→Ln-1→L2→Ln-2→…

// 你不能只是单纯的改变节点内部的值，而是需要实际的进行节点交换。

// 示例 1:

// 给定链表 1->2->3->4, 重新排列为 1->4->2->3.
// 示例 2:

// 给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

#include <stack>

using namespace std;

// Definition for singly-linked list.
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution1 {
public:
    void reorderList(ListNode* head) {
        if (!head || !head->next || !head->next->next) return;

        // 快慢指针找到链表中点，从中点处断开
        ListNode* fast = head;
        ListNode* slow = head;
        while (fast->next && fast->next->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* mid = slow->next;
        slow->next = nullptr;

        // 将第二个链表翻转
        ListNode* last = mid;
        ListNode* pre = nullptr;
        while (last) {
            ListNode* next = last->next;
            last->next = pre;
            pre = last;
            last = next;
        }

        // 将第二个链表间隔的插入第一个链表
        while (head && pre) {
            ListNode* next = head->next;
            head->next = pre;
            pre = pre->next;
            head->next->next = next;
            head = next;
        }
    }
};

// 使用栈
class Solution {
public:
    void reorderList(ListNode* head) {
        if (!head || !head->next || !head->next->next) return;
        stack<ListNode*> s{};
        ListNode* cur = head;
        while (cur) {
            s.push(cur);
            cur = cur->next;
        }
        int count = (s.size() - 1) / 2; // 出栈节点个数
        cur = head;
        while (count-- > 0) {
            auto t = s.top();
            s.pop();
            ListNode* next = cur->next;
            cur->next = t;
            t->next = next;
            cur = next;
        }
        s.top()->next = nullptr; // 断开栈顶节点
    }
};

// 不停的找尾巴
class Solution {
public:
    void reorderList(ListNode* head) {
        ListNode* cur{head};
        while (cur && cur->next) {
            ListNode* newTail{cur};
            while (newTail->next->next != nullptr) {
                newTail = newTail->next;
            }
            ListNode* tail = newTail->next;
            if (tail != cur && tail != cur->next) {
                newTail->next = nullptr;
                tail->next = cur->next;
                cur->next = tail;
                cur = cur->next->next;
            } else {
                break;
            }
        }
    }
};

// 找中点，逆序，合并
class Solution {
public:
    void reorderList(ListNode* head) {
        if (nullptr == head) {
            return;
        }
        ListNode* mid = middleNode(head);
        ListNode* l1 = head;
        ListNode* l2 = mid->next;
        mid->next = nullptr;
        l2 = reverseList(l2);
        mergeList(l1, l2);
    }
private:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow{head};
        ListNode* fast{head};
        while (fast->next && fast->next->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
    ListNode* reverseList(ListNode* head) {
        ListNode* newHead{nullptr};
        ListNode* cur{head};
        while (cur) {
            ListNode* temp = cur->next;
            cur->next = newHead;
            newHead = cur;
            cur = temp;
        }
        return newHead;
    }
    void mergeList(ListNode* l1, ListNode* l2) {
        ListNode* l1_temp{nullptr};
        ListNode* l2_temp{nullptr};
        while (l1 && l2) {
            l1_temp = l1->next;
            l2_temp = l2->next;

            l1->next = l2;
            l2->next = l1_temp;
            l1 = l1_temp;
            l2 = l2_temp;
        }
    }
};